package com.mingyuean.demo.simple;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.File;
import java.net.URL;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author MingYueAn
 * <p> Spring容器：ApplicationContext应用上下文类
 * <p> 2023/3/10 17:09
 * @version: 1.0
 */
public class ApplicationContext {

    private static final Logger log = LoggerFactory.getLogger(ApplicationContext.class);

    /**
     * 配置类
     */
    private Class configClass;
    /**
     * 存放BeanDefinition的容器，以Bean的名称为key，BeanDefinition为value
     */
    private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();

    /**
     * 构造函数，初始化ApplicationContext
     *
     * @param configClass 配置类
     */
    public ApplicationContext(Class configClass) {
        this.configClass = configClass;
        // 判断configClass上是否存在ComponentScan注解
        if (configClass.isAnnotationPresent(ComponentScan.class)) {
            // 获取注解
            final ComponentScan componentScan = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
            // 获取注解上定义的扫描路径
            // com.mingyuean.demo.service
            String path = componentScan.value();
            // com/mingyuean/demo/service
            path = path.replace(".", "/");
            log.debug("路径：{}", path);
            // 获取类加载器
            final ClassLoader classLoader = ApplicationContext.class.getClassLoader();
            // 通过类加载器获取存放class的绝对路径
            final URL resource = classLoader.getResource(path);
            // 通过绝对路径来生成File
            final File file = new File(resource.getFile());
            log.debug("文件：{}", file);
            // 获取class的根路径
            final String rootPath = getClass().getResource("/")
                    .getPath()
                    .replaceFirst("/", "")
                    .replace("/", "\\");
            log.debug("根路径：{}", rootPath);
            // 判断File是否为文件夹
            if (file.isDirectory()) {
                // 获取文件夹中所有文件
                final File[] listFiles = file.listFiles();
                // 遍历全部的文件，获取文件的绝对路径
                for (File f : listFiles) {
                    String absolutePath = f.getAbsolutePath();
                    // 判断这些文件的是否是以.class结尾
                    if (absolutePath.endsWith(".class")) {
                        // 需要将绝对路径转换成为全类名
                        String className = absolutePath
                                .replace(rootPath, "")
                                .replace("\\", ".")
                                .replace(".class", "");
                        log.debug("绝对路径：{}",absolutePath);
                        log.debug("className = {}", className);
                        try {
                            // 通过类加载器，根据全类名获取class
                            final Class<?> aClass = classLoader.loadClass(className);
                            // 判断class上是否存在注解Component，存在生成BeanDefinition
                            if (aClass.isAnnotationPresent(Component.class)) {
                                // 生成BeanDefinition
                                System.out.println("生成BeanDefinition");
                                final BeanDefinition beanDefinition = new BeanDefinition();
                                // 设置BeanDefinition的类型
                                beanDefinition.setType(aClass);
                                // 判断是否存在注解Scope，不存在将会默认设置成单例
                                if (aClass.isAnnotationPresent(Scope.class)) {
                                    // 获取注解Scope的值
                                    final Scope scope = aClass.getAnnotation(Scope.class);
                                    beanDefinition.setScope(scope.value());
                                } else {
                                    beanDefinition.setScope("singleton");
                                }
                                // 获取Component注解的值，作为Bean的名称
                                final String beanName = aClass.getAnnotation(Component.class).value();
                                // 存入容器
                                beanDefinitionMap.put(beanName, beanDefinition);
                                // TODO: 2023/3/10 测试
                                final BeanDefinition userService = beanDefinitionMap.get("userService");
                                System.out.println("userService = " + userService);
                            }
                        } catch (ClassNotFoundException e) {
                            e.printStackTrace();
                        }

                    }
                }
            }
        }
    }


    public Object getBean(String userService) {
        return null;
    }
}
